home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 1997 December / PC Pro December 1997 CD-Rom coverdisc.iso / code / IDEPeek.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-09-08  |  6.8 KB  |  238 lines

  1. unit IDEPeek;
  2.  
  3. interface
  4.  
  5. uses Windows, SysUtils, Classes, Forms, Menus, Dialogs, ComCtrls,
  6.      ExtCtrls;
  7.  
  8. type
  9.     TIDE = class (TObject)
  10.     private
  11.         fd: Integer;
  12.         FieldList: TStringList;
  13.     public
  14.         AppBuilder: TForm;                         { main IDE window }
  15.         procedure WriteStr (const Str: String);
  16.         procedure DumpClassInfo (Comp: TComponent);
  17.         procedure DumpFieldList (Ptr: PChar);
  18.         procedure DumpMethodList (const clsName: String; Ptr: PChar);
  19.         function TypeFromClassList (ClassList: PChar; Index: Integer): String;
  20.         procedure CallClickMethod (Obj: TObject; const MethodName: String);
  21.         constructor Create;
  22.         destructor Destroy; override;
  23.     end;
  24.  
  25. var
  26.     IDE: TIDE;
  27.  
  28. implementation
  29.  
  30. const
  31.     AppBuilderInstanceSize = 1164;     { Version 3, Build 5.53 }
  32.  
  33. function GetFieldTable (Obj: TObject): Pointer; assembler;
  34. asm
  35.     mov     eax,[eax]                   { get class pointer }
  36.     mov     eax,[eax].vmtFieldTable     { get field list  }
  37. end;
  38.  
  39. function GetMethodTable (Obj: TObject): Pointer; assembler;
  40. asm
  41.     mov     eax,[eax]                   { get class pointer }
  42.     mov     eax,[eax].vmtMethodTable    { get method list   }
  43. end;
  44.  
  45. function Pad (const Str: String; Width: Integer): String;
  46. begin
  47.     Result := Str;
  48.     while Length (Result) < Width do Result := Result + ' ';
  49. end;
  50.  
  51. constructor TIDE.Create;
  52. var
  53.     S: String;
  54.     Idx: Integer;
  55.     Comp: TComponent;
  56. begin
  57.     Inherited Create;
  58.     FieldList := TStringList.Create;
  59.  
  60.     fd := _lcreat ('c:\ide.pas', 0);
  61.     if fd = -1 then
  62.        raise Exception.Create ('Can''t create output file');
  63.  
  64.     try
  65.         for Idx := 0 to Application.ComponentCount - 1 do
  66.         begin
  67.             Comp := Application.Components [Idx];
  68.             S := Format ('    %s: %s;', [Comp.Name, Comp.ClassName]);
  69.             if Comp is TMenuItem then S := S + ' (' + TMenuItem(Comp).Caption + ')';
  70.             WriteStr (S);
  71.         end;
  72.  
  73.         WriteStr ('');
  74.  
  75.         AppBuilder := Application.FindComponent ('AppBuilder') as TForm;
  76.         if AppBuilder.InstanceSize <> AppBuilderInstanceSize then
  77.             raise Exception.Create ('Unknown IDE version - expected Build 5.53');
  78.  
  79.         { List all the components owned by AppBuilder }
  80.         DumpClassInfo (AppBuilder);
  81.  
  82.         for Idx := 0 to AppBuilder.ComponentCount - 1 do
  83.         begin
  84.             Comp := AppBuilder.Components [Idx];
  85.             { If not already dealt with }
  86.             if FieldList.IndexOf (Comp.Name) = -1 then
  87.                 if Comp.Name <> '' then
  88.                     WriteStr (Format ('    %s: %s;', [Comp.Name, Comp.ClassName]));
  89.         end;
  90.  
  91.     finally
  92.         _lclose (fd);
  93.     end;
  94.  
  95.     { This is an example of how to call a built-in method }
  96.     CallClickMethod (AppBuilder, 'ViewsAlignPalette');
  97.  
  98.     { Indicate that the package is loaded }
  99.     MessageBeep (0);
  100. end;
  101.  
  102. procedure TIDE.CallClickMethod (Obj: TObject; const MethodName: String);
  103. var
  104.     pp: Pointer;
  105. begin
  106.     pp := Obj.MethodAddress (MethodName);
  107.     if pp = Nil then Exit;
  108.     asm
  109.         push    eax
  110.         push    edx
  111.         push    ebx
  112.         mov     edx,Self
  113.         mov     eax,Obj
  114.         mov     ebx,pp
  115.         call    ebx
  116.         pop     ebx
  117.         pop     edx
  118.         pop     eax
  119.     end;
  120. end;
  121.  
  122. procedure TIDE.WriteStr (const Str: String);
  123. begin
  124.     _lwrite (fd, @Str[1], Length (Str));
  125.     _lwrite (fd, #13 + #10, 2);
  126. end;
  127.  
  128. function TIDE.TypeFromClassList (ClassList: PChar; Index: Integer): String;
  129. var
  130.     cls: TClass;
  131. begin
  132.     { Validate index }
  133.     if Index >= PWord (ClassList)^ then raise Exception.Create ('Invalid classlist index');
  134.     Inc (ClassList, sizeof (Word));
  135.     Inc (ClassList, sizeof (Pointer) * Index);
  136.     Result := TObject (PInteger (ClassList)^).ClassName;
  137. end;
  138.  
  139. procedure TIDE.DumpFieldList (Ptr: PChar);
  140. var
  141.     Idx: Integer;
  142.     FieldCount: Integer;
  143.     ClassList: Pointer;
  144.     Offset: Integer;
  145.     Index: Word;
  146.     ps: ^ShortString absolute Ptr;
  147. begin
  148.     FieldCount := PWord (Ptr)^;
  149.     { If no fields defined, then get out }
  150.     if FieldCount <> 0 then begin
  151.         { Print field count }
  152.         WriteStr (Format ('Field count = %d', [FieldCount]));
  153.         { Skip over the field count word }
  154.         Inc (Ptr, sizeof (Word));
  155.         { Stash the ClassList pointer and jump over it }
  156.         ClassList := Pointer (PInteger (Ptr)^);
  157.         Inc (Ptr, sizeof (Pointer));
  158.         { Now iterate through the various fields }
  159.         for Idx := 0 to FieldCount - 1 do
  160.         begin
  161.             { Stash the offset into the class }
  162.             Offset := PInteger (Ptr)^;
  163.             Inc (Ptr, sizeof (Integer));
  164.             { Stash the class list type index }
  165.             Index := PWord (Ptr)^;
  166.             Inc (Ptr, sizeof (Word));
  167.             FieldList.Add (ps^);
  168.             WriteStr (Pad (ps^ + ': ' + TypeFromClassList (ClassList, Index) + ';', 60) + Format ('{ $%s }', [IntToHex (Offset, 8)]));
  169.             Inc (Ptr, Length (ps^) + 1);
  170.         end;
  171.     end;
  172. end;
  173.  
  174. procedure TIDE.DumpMethodList (const clsName: String; Ptr: PChar);
  175. var
  176.     Idx: Integer;
  177.     MethodCount: Integer;
  178.     ProcAddress: Integer;
  179.     ps: ^ShortString absolute Ptr;
  180. begin
  181.     MethodCount := PWord (Ptr)^;
  182.     { If no methods defined, then get out }
  183.     if MethodCount <> 0 then begin
  184.         { Print method count }
  185.         WriteStr (Format ('Method count = %d', [MethodCount]));
  186.         { Skip over the method count word }
  187.         Inc (Ptr, sizeof (Word));
  188.         { Now iterate through the various fields }
  189.         for Idx := 0 to MethodCount - 1 do
  190.         begin
  191.             { Skip entry size info }
  192.             Inc (Ptr, sizeof (Word));
  193.             ProcAddress := PInteger (Ptr)^;
  194.             Inc (Ptr, sizeof (Integer));
  195.             WriteStr (Format ('%s.%s @ $%s', [clsName, ps^, IntToHex (ProcAddress, 8)]));
  196.             Inc (Ptr, Length (ps^) + 1);
  197.         end;
  198.     end;
  199. end;
  200.  
  201. procedure TIDE.DumpClassInfo (Comp: TComponent);
  202. var
  203.     ClassPtr: PByte;
  204.     clsName: String;
  205.     ps: ^ShortString absolute ClassPtr;
  206.     cls: ^TClass absolute ClassPtr;
  207. begin
  208.     ClassPtr := Comp.ClassInfo;
  209.     if ClassPtr^ <> 7 then raise Exception.Create ('Invalid class ptr');
  210.     WriteStr (Format ('%s = class (%s)', [Comp.ClassName, Comp.ClassParent.ClassName]));
  211.  
  212.     Inc (ClassPtr);  WriteStr ('');
  213.     clsName := ps^;
  214.     WriteStr (Format ('Class Information for "%s"', [clsName]));
  215.     Inc (ClassPtr, Length (clsName) + 11);
  216.     WriteStr (Format ('Source File = "%s.Pas"', [ps^]));
  217.  
  218.     DumpFieldList (GetFieldTable (Comp));
  219.     DumpMethodList (clsName, GetMethodTable (Comp));
  220. end;
  221.  
  222. destructor TIDE.Destroy;
  223. begin
  224.     FieldList.Free;
  225.     Inherited Destroy;
  226. end;
  227.  
  228. initialization
  229.     IDE := TIDE.Create;
  230. finalization
  231.     IDE.Free;
  232. end.
  233.  
  234.  
  235.  
  236.  
  237.  
  238.